package com.real_aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 切面
 *      切入点和通知组成
 *
 *          切入点:定义要拦截哪些类的哪些方法
 *          通知:定义拦截之后方法要做什么
 */
@Component
@Aspect  //声明当前类为切面
public class LogCut {
    /**
     * 切入点:
     *      匹配规则。规定什么方法被拦截、需要处理什么方法
     * 定义切入点
     *      @Pointcut(""匹配规则"")
     *
     *      Aop切入点表达式简介
     *          1．执行任意公共方法:
     *              execution(public *(..))
     *          2．执行任意的set方法
     *              execution(* set*(..))
     *          3．执行com.xxxx.service包下任意类的任意方法
     *              execution(* com.xxxx.service.*.*(..))
     *          4．执行com.xxxx.service包以及子包下任意类的任意方法
     *              execution(* com.xxxx.service..*.*(..))
     */
    @Pointcut("execution(* com.real_aop.service..*.*(..))") //切入点
    public void cut01(){

    }

    /**
     * 前置通知
     *      目标方法执行前，执行该通知
     */
    @Before(value = "cut01()")
    public void before(){
        System.out.println("前置通知");
    }

    /**
     * 返回通知
     *      目标类的方法在无异常执行后，执行该通知
     */
    @AfterReturning(value = "cut01()")
    public void afterReturning(){
        System.out.println("返回通知");
    }

    /**
     * 最终通知
     *      目标类的方法在执行后，执行该通知(不管是否有无异常)
     */
    @After(value = "cut01()")
    public void after(){
        System.out.println("最终通知");
    }

    /**
     * 异常通知
     *      目标类的方法在执行异常后，执行该通知
     */
    @AfterThrowing(value = "cut01()",throwing = "e")
    public void afterThrowing(Exception e){
        System.out.println("异常通知====异常原因:"+e.getMessage());
    }

    /**
     * 环绕通知
     *      目标类的方法执行前后，都可以通过环绕通知定义响应的处理
     *          需要通过显示调用的方法，否则无法访问指定方法 point.proceed()
     *
     * @param point
     * @return
     */
    @Around(value = "cut01()")
    public Object around(ProceedingJoinPoint point){
        System.out.println("环绕通知前置通知");

        Object object = null;
        try {
            //显示调用对应的方法
            object = point.proceed();
            System.out.println(point.getTarget());
            System.out.println("环绕通知返回通知");//方法执行完后执行
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知异常通知");
        }
        System.out.println("环绕通知最终通知");
        return object;
    }

}
